package com.ly.auth.config;

import com.ly.auth.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.*;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.List;


@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    //从WebSecurityConfig中获取的
    @Autowired
    private AuthenticationManager authenticationManager;

    //本类中的，授权码模式需要
    @Autowired
    private AuthorizationCodeServices authorizationCodeServices;

    //TokenConfig中的
    @Autowired
    private TokenStore tokenStore;

    //从WebSecurityConfig中获取的
    @Autowired
    private PasswordEncoder passwordEncoder;

    //本类中的

    /*@Autowired
    private ClientDetailsService clientDetailsService;*/

    @Autowired
    private ClientDetailsService customClientDetailsService;

    //TokenConfig中的
    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;

    @Autowired
    private TokenEnhancer jwtTokenEnhancer;

    @Autowired
    private UserService userService;



    /**
     * 用来配置令牌端点的安全约束
     *
     * @param security
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.tokenKeyAccess("permitAll()")            // /oauth/token_key 提供公有密匙的端点 允许任何人访问
                .checkTokenAccess("permitAll()")          // /oauth/check_token ：用于资源服务访问的令牌解析端点 允许任何人访问
                .allowFormAuthenticationForClients();   //表单认证（申请令牌）,允许通过form传递client_id和client_secret，否则只能通过Authorization Basic Auth方式。
    }

    /**
     * 用来配置客户端详情服务,客户端详情信息在这里进行初始化,
     * 你能够把客户端详情信息写死在这里或者是通过数据库来存储调取详情信息
     *
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(customClientDetailsService);
        //clients.withClientDetails(clientDetailsService);
    }

    /**
     * 用来配置令牌（token）的访问端点（url）和令牌服务(token services)
     *
     * @param endpoints
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager) //认证管理器,密码模式需要
                .userDetailsService(userService) //刷新令牌获取新令牌时需要
                .authorizationCodeServices(authorizationCodeServices) //授权码管理策略，针对授权码模式有效，会将授权码放到 auth_code表，授权后就会删除它
                .tokenServices(tokenService()) //令牌管理策略
                .allowedTokenEndpointRequestMethods(HttpMethod.POST);   //允许post提交
    }



    @Bean
    public AuthorizationCodeServices authorizationCodeServices(DataSource dataSource) {
        //设置授权码模式的授权码从数据库中获取
        return new JdbcAuthorizationCodeServices(dataSource);
    }

    //客户端详情服务，从数据库中获取
    /* 使用了自定义customClientDetailsService
    @Bean
    public ClientDetailsService clientDetailsService(DataSource dataSource) {
        ClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
        ((JdbcClientDetailsService)clientDetailsService).setPasswordEncoder(passwordEncoder);
        return clientDetailsService;
    }*/

    //令牌管理服务
    @Bean
    public AuthorizationServerTokenServices tokenService() {
        DefaultTokenServices service = new DefaultTokenServices();
        //客户端信息服务
        //service.setClientDetailsService(clientDetailsService);
        service.setClientDetailsService(customClientDetailsService);

        //支持自动刷新
        service.setSupportRefreshToken(true);
        service.setTokenStore(tokenStore);
        //令牌增强
        //TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        //tokenEnhancerChain.setTokenEnhancers(Arrays.asList(jwtAccessTokenConverter));
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        List<TokenEnhancer> enhancers = new ArrayList<>();
        enhancers.add(jwtTokenEnhancer);
        enhancers.add(jwtAccessTokenConverter);
        tokenEnhancerChain.setTokenEnhancers(enhancers);

        service.setTokenEnhancer(tokenEnhancerChain);
        //令牌默认有效期2小时
        service.setAccessTokenValiditySeconds(7200);
        //刷新令牌默认有效期3天
        service.setRefreshTokenValiditySeconds(259200);
        return service;
    }
}
